import datetime
import functools
import glob
import json
import os
import re
import subprocess
import sys
import tempfile
import itertools

from numpy import arange as rng

import cc.appcoin2.strategy.sim_driver as sdriver
from itertools import product  # noqa: F401
from cc.appcoin2.strategy.sparams.lmparamset import (  # noqa: F401
    strategy_name,
    strategy_name_gt,
    strategy_group,
    cartesian,
    xylm_regex
)
from python.coin_deploy.lm_search.filter.lmfilter import (
    agg_template
)


# usage:
# cross(cartesian(x=[0,1]),[{}]+cartesian(a=[1,2]))
'''
   x    a
0  0  NaN
1  0  1.0
2  0  2.0
3  1  NaN
4  1  1.0
5  1  2.0
'''
def cross(*args):
  rets = []
  for instance in itertools.product(*args):
    comb_dict = {}
    for each_dict in instance:
      comb_dict.update(each_dict)
    if comb_dict not in rets:
      rets.append(comb_dict)
  return rets


def get_config_files(config_path_expr=None, **kwargs):
  if 'strategy_name' in kwargs:
    return strategy_name(kwargs['strategy_name'])
  try:
    config_files = eval(config_path_expr)
  except Exception as exc:
    config_files = glob.glob(config_path_expr)
    if len(config_files) == 0:
      raise exc
  return config_files


def get_config_files_has_symbol(config_files, sim_type, pick_symbol_regex):
  for config_file in config_files:
    if pick_symbol_regex is not None and sim_type == 'lm':
      confobj = json.load(open(config_file))
      found = False
      for key in confobj['products'].keys():
        if re.match(pick_symbol_regex, key):
          found = True
          break
      if found:
        yield config_file
    else:
      yield config_file


def get_sparams(sparams_expr):
  if sparams_expr is not None:
    sparams = eval(sparams_expr)
  else:
    sparams = [{}]
  return sparams


def get_batch_driver(slurm_cpu, cpu, tmp_work_root):
  if slurm_cpu is not None and slurm_cpu > 0:
    slurm_temp_dir = tmp_work_root
    num_cpu = slurm_cpu
    batch_runner = functools.partial(sdriver.batch_slurm, temp_dir=slurm_temp_dir)
  else:
    slurm_temp_dir = None
    num_cpu = cpu
    batch_runner = sdriver.batch_local
  return slurm_temp_dir, num_cpu, batch_runner


def create_temp_file_and_dump_json(dir, prefix, suffix, data):
  fd, path = tempfile.mkstemp(prefix=prefix, suffix=suffix, dir=dir)
  if data is not None:
    with open(fd, 'w') as f:
      json.dump(data, f, indent=2)
  else:
    os.close(fd)
  return path


def get_git_info(path):
  output = f'\n##### {path} git info #####'
  try:
    git_info = subprocess.getoutput(
        f'git -C {path} diff HEAD && git -C {path} log --graph --decorate --pretty=oneline --abbrev-commit | head -10')
    output = output + f'\n{git_info}'
  except:
    pass
  return output


def dump_runsim_command(result_dir):
  os.makedirs(result_dir, exist_ok=True)
  run_command = ' '.join([
      './pyrunner', os.path.relpath(sys.argv[0])]
      + [repr(arg) for arg in sys.argv[1:]])

  git_infos = []
  for git_dir in ['.', 'python/coin_deploy', '../coin_binary', '../teamy_coin']:
    if os.path.exists(git_dir):
      git_infos.append(get_git_info(git_dir))
  git_info = '\n'.join(git_infos)

  suffix = datetime.datetime.now().strftime('%Y%m%d_%H%M%S.%f.txt')
  with open(f'{result_dir}/command_{suffix}', 'w') as fo:
    fo.write(run_command)
    fo.write(git_info)
